home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Tool Chest / Text / WASTE 1.3a6 / Demo / Source / WEDemoWindows.c < prev   
Encoding:
C/C++ Source or Header  |  1997-12-01  |  26.2 KB  |  1,119 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     Window Handling
  4.  
  5.     Copyright © 1993-1997 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __ALIASES__
  13. #include <Aliases.h>
  14. #endif
  15.  
  16. #ifndef __ERRORS__
  17. #include <Errors.h>
  18. #endif
  19.  
  20. #ifndef __FIXMATH__
  21. #include <FixMath.h>
  22. #endif
  23.  
  24. #ifndef __TOOLUTILS__
  25. #include <ToolUtils.h>
  26. #endif
  27.  
  28. #ifndef __FILETYPESANDCREATORS__
  29. #include <FileTypesAndCreators.h>
  30. #endif
  31.  
  32. #ifndef _LongCoords_
  33. #include "LongCoords.h"
  34. #endif
  35.  
  36. #ifndef __WEDEMOAPP__
  37. #include "WEDemoIntf.h"
  38. #endif
  39.  
  40. #ifndef __SMARTSCROLLAPI__
  41. #include "SmartScroll.h"
  42. #endif
  43.  
  44. // some consts used by DoGrow()
  45.  
  46. enum {
  47.     kMinWindowWidth        = 200,
  48.     kMinWindowHeight    = 80
  49. };
  50.  
  51. // static variables
  52.  
  53. static SInt32 sScrollStep; // how many pixels to scroll (used by ScrollProc)
  54.  
  55.  
  56. static void    CalcGrowIconRect( WindowRef window, Rect *iconRect )
  57. {
  58.     Rect portRect = GetWindowPort( window )->portRect;
  59.  
  60.     iconRect->top = portRect.bottom - (kBarWidth - 2);
  61.     iconRect->left = portRect.right - (kBarWidth - 2);
  62.     iconRect->bottom = portRect.bottom;
  63.     iconRect->right = portRect.right;
  64. }
  65.  
  66. static void    CalcTextRect( WindowRef window, Rect *textRect )
  67. {
  68.     Rect portRect = GetWindowPort( window )->portRect;
  69.  
  70.     textRect->top = 0;
  71.     textRect->left = 0;
  72.     textRect->bottom = portRect.bottom - (kBarWidth - 1);
  73.     textRect->right = portRect.right - (kBarWidth - 1);
  74.     InsetRect( textRect, kTextMargin, kTextMargin );
  75. }
  76.  
  77. static void    CalcScrollBarRect( WindowRef window, Orientation orientation, Rect *barRect )
  78. {
  79.     Rect portRect = GetWindowPort( window )->portRect;
  80.  
  81.     switch ( orientation )
  82.     {
  83.         case kVertical :
  84.         {
  85.             barRect->top = -1;
  86.             barRect->left = portRect.right - (kBarWidth - 1);
  87.             barRect->bottom = portRect.bottom - (kBarWidth - 2);
  88.             barRect->right = portRect.right + 1;
  89.             break;
  90.         }
  91.  
  92.         case kHorizontal :
  93.         {
  94.             barRect->top = portRect.bottom - (kBarWidth - 1);
  95.             barRect->left = -1;
  96.             barRect->bottom = portRect.bottom + 1;
  97.             barRect->right = portRect.right - (kBarWidth - 2 );
  98.             break;
  99.         }
  100.     }
  101. }
  102.  
  103. /*
  104.     the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon
  105.     to the left and top margins of the window's content area
  106.     these additional lines may create ugly dirt, so we use this routine to temporarily
  107.     set the clip region to the grow icon rect.
  108.  
  109.     in addition, if validate is true, we call _ValidRect on the icon rect
  110. */
  111.  
  112. static void    MyDrawGrowIcon( WindowRef window, Boolean validate )
  113. {
  114.     GrafPtr        savePort;
  115.     RgnHandle    saveClip;
  116.     Rect        r;
  117.  
  118.     // save port and set thePort to wind
  119.  
  120.     GetPort( &savePort );
  121.     SetPortWindowPort( window );
  122.  
  123.     // save the clip region
  124.  
  125.     saveClip = NewRgn();
  126.     GetClip( saveClip );
  127.  
  128.     // calculate the grow icon rect
  129.  
  130.     CalcGrowIconRect( window, &r );
  131.  
  132.     // set clip region to grow icon rect
  133.  
  134.     ClipRect( &r );
  135.  
  136.     // call _DrawGrowIcon
  137.  
  138.     DrawGrowIcon( window );
  139.  
  140.     // if validate is true, remove the grow icon rect from the update region
  141.  
  142.     if ( validate )
  143.         ValidRect( &r );
  144.  
  145.     // restore old clip region
  146.  
  147.     SetClip( saveClip );
  148.     DisposeRgn( saveClip );
  149.  
  150.     // restore old port
  151.  
  152.     SetPort( savePort );
  153. }
  154.  
  155. static void    ScrollBarChanged( WindowRef window )
  156. {
  157.     // scroll text to reflect new scroll bar setting
  158.  
  159.     DocumentHandle hDocument = GetWindowDocument( window );
  160.     WEReference    we;
  161.     LongRect viewRect, destRect;
  162.  
  163.     we = (*hDocument)->we;
  164.     WEGetViewRect( &viewRect, we );
  165.     WEGetDestRect( &destRect, we );
  166.     WEScroll
  167.     (
  168.         viewRect.left - destRect.left - LCGetValue( (*hDocument)->scrollBars[ kHorizontal ] ),
  169.         viewRect.top - destRect.top - LCGetValue( (*hDocument)->scrollBars[ kVertical ] ),
  170.         we
  171.     );
  172. }
  173.  
  174. static void    AdjustBars ( WindowRef window )
  175. {
  176.     DocumentHandle    hDocument ;
  177.     WEReference        we ;
  178.     GrafPtr            savePort ;
  179.     LongRect        viewRect, destRect ;
  180.     SInt32            visible, total, value, max ;
  181.     ControlRef        bar ;
  182.  
  183.     GetPort ( & savePort ) ;
  184.     SetPortWindowPort ( window ) ;
  185.  
  186.     hDocument = GetWindowDocument ( window ) ;
  187.     we = ( * hDocument ) -> we ;
  188.  
  189.     // get the view and destination rectangle
  190.     WEGetViewRect ( & viewRect, we ) ;
  191.     WEGetDestRect ( & destRect, we ) ;
  192.  
  193.     //    do the vertical axis
  194.  
  195.     //    get scroll bar handle
  196.     bar = ( * hDocument ) -> scrollBars [ kVertical ] ;
  197.  
  198.     //    calculate new scroll bar settings
  199.  
  200.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  201.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  202.  
  203.     total = destRect . bottom - destRect . top ;    //    total pixel height
  204.     visible = viewRect . bottom - viewRect . top ;    //    visible pixel height
  205.     max = total - visible ;                            //    scrollable range (in pixels)
  206.     value = viewRect . top - destRect . top ;        //    thumb location within scrollable range
  207.  
  208.     //    make sure max is always non-negative
  209.     if ( max <= 0 ) max = 0 ;
  210.  
  211.     //    notify SmartScroll
  212.     SetSmartScrollInfo ( bar, visible, total ) ;
  213.  
  214.     //    reset the scroll bar
  215.     LCSetMax ( bar, max ) ;
  216.     LCSetValue ( bar, value ) ;
  217.  
  218.     //    if value exceeds max then the bottom of the destRect is above
  219.     //    the bottom of the view rectangle:  we need to scroll the text downward
  220.     if ( value > max )
  221.     {
  222.         ScrollBarChanged ( window ) ;
  223.     }
  224.  
  225.     //    now do the horizontal axis
  226.  
  227.     //    get scroll bar handle
  228.     bar = ( * hDocument ) -> scrollBars [ kHorizontal ] ;
  229.  
  230.     //    calculate new scroll bar settings
  231.     total = destRect . right - destRect . left ;    //    total pixel width
  232.     visible = viewRect . right - viewRect . left ;    //    visible pixel width
  233.     max = total - visible ;                            //    scrollable range (in pixels)
  234.     value = viewRect . left - destRect . left ;        //    thumb location within scrollable range
  235.  
  236.     //    make sure max is always non-negative
  237.     if ( max <= 0 ) max = 0 ;
  238.  
  239.     //    notify SmartScroll
  240.     SetSmartScrollInfo ( bar, visible, total ) ;
  241.  
  242.     //    reset the scroll bar
  243.     LCSetMax ( bar, max ) ;
  244.     LCSetValue ( bar, value ) ;
  245.  
  246.     SetPort ( savePort ) ;
  247. }
  248.  
  249. static void    ViewChanged( WindowRef window )
  250. {
  251.     DocumentHandle    hDocument;
  252.     GrafPtr            savePort;
  253.     ControlRef        bar;
  254.     Rect            r;
  255.     LongRect        viewRect;
  256.     Orientation        orientation;
  257.  
  258.     GetPort( &savePort );
  259.     SetPortWindowPort( window );
  260.  
  261.     hDocument = GetWindowDocument( window );
  262.  
  263.     //    resize the text area
  264.  
  265.     CalcTextRect( window, &r );
  266.     WERectToLongRect( &r, &viewRect );
  267.     WESetViewRect( &viewRect, (*hDocument)->we );
  268.  
  269.     //     move and resize the control bars
  270.  
  271.     for ( orientation = kVertical; orientation <= kHorizontal; orientation++ )
  272.     {
  273.         bar = (*hDocument)->scrollBars[ orientation ];
  274.         CalcScrollBarRect( window, orientation, &r );
  275.         MoveControl( bar, r.left, r.top );
  276.         SizeControl( bar, r.right - r.left, r.bottom - r.top );
  277.         ValidRect( &r );
  278.     }
  279.  
  280.     //    reset the thumb positions and the max values of the control bars
  281.     AdjustBars( window );
  282.  
  283.     //    redraw the control bars
  284.  
  285.     ShowControl( (*hDocument)->scrollBars[ kVertical ] );
  286.     ShowControl( (*hDocument)->scrollBars[ kHorizontal ] );
  287.  
  288.     SetPort( savePort );
  289. }
  290.  
  291. /*
  292.     This is a deviation from the original Pascal WASTE Demo App code.
  293.  
  294.     This "morally correct" code for window dragging is per an article in MacTech
  295.     Magazine (July 1994, Vol 10, No. 7). by Eric Shapiro (of Rock Ridge Enterprises)
  296.     called "Multiple Monitors vs. Your Application"
  297.  
  298.     Eric addressed numerous things to allow your app to deal nicely with multiple
  299.     monitor setups, one of them is dragging.
  300.  
  301.     According to Eric, many apps don't let you drag windows to second monitors, and
  302.     though holding down the cmd/opt keys often overrides this problem, it should
  303.     still be updated.  And the only reason qd.screenBits.bounds works to allow
  304.     you to drag to second monitors is because of a kludge Apple put in the Window Manager
  305.  
  306.     So, this is some code from Eric to make our app be "morally correct" :)
  307. */
  308.  
  309. void DoDrag ( Point thePoint, WindowRef window )
  310. {
  311.     Rect desktopBounds ;
  312.  
  313.     if ( gHasColorQD )
  314.     {
  315.         desktopBounds = ( * GetGrayRgn ( ) ) -> rgnBBox ;
  316.     }
  317.     else
  318.     {
  319.         desktopBounds = qd . screenBits . bounds ;
  320.     }
  321.  
  322.     DragWindow ( window, thePoint, & desktopBounds ) ;
  323. }
  324.  
  325. void Resize ( Point newSize, WindowRef window )
  326. {
  327.     DocumentHandle    hDocument ;
  328.     GrafPtr            savePort ;
  329.     Rect            r ;
  330.     RgnHandle        tempRgn, dirtyRgn ;
  331.  
  332.     //    set up the port
  333.     GetPort( & savePort ) ;
  334.     SetPortWindowPort ( window ) ;
  335.  
  336.     hDocument = GetWindowDocument ( window ) ;
  337.  
  338.     //    create temporary regions for calculations
  339.     tempRgn = NewRgn ( ) ;
  340.     dirtyRgn = NewRgn ( ) ;
  341.  
  342.     //    save old text region
  343.     CalcTextRect ( window, & r ) ;
  344.     RectRgn ( tempRgn, & r ) ;
  345.  
  346.     //    erase the old grow icon rect
  347.     CalcGrowIconRect ( window, & r ) ;
  348.     EraseRect ( & r ) ;
  349.  
  350.     //    hide the scroll bars
  351.     HideControl ( ( * hDocument ) -> scrollBars [ kVertical ] ) ;
  352.     HideControl ( ( * hDocument ) -> scrollBars [ kHorizontal ] ) ;
  353.  
  354.     //    perform the actual resizing of the window, redraw scroll bars and grow icon
  355.     SizeWindow ( window, newSize . h, newSize . v, false ) ;
  356.     ViewChanged ( window ) ;
  357.     MyDrawGrowIcon ( window, true ) ;
  358.  
  359.     //    calculate the dirty region (to be updated)
  360.     CalcTextRect ( window, & r );
  361.     RectRgn ( dirtyRgn, & r ) ;
  362.     XorRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;
  363.     InsetRect ( & r, - kTextMargin, - kTextMargin ) ;
  364.     RectRgn ( tempRgn, & r ) ;
  365.     SectRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;
  366.  
  367.     //    mark the dirty region as invalid
  368.     InvalRgn ( dirtyRgn ) ;
  369.  
  370.     //    throw away temporary regions
  371.     DisposeRgn ( tempRgn ) ;
  372.     DisposeRgn ( dirtyRgn ) ;
  373.  
  374.     //    restore the port
  375.     SetPort ( savePort ) ;
  376. }
  377.  
  378. void DoGrow ( Point hitPt, WindowRef window )
  379. {
  380.     Rect sizeRect ;
  381.     SInt32 newSize ;
  382.  
  383.     SetRect( & sizeRect, kMinWindowWidth, kMinWindowHeight, SHRT_MAX, SHRT_MAX ) ;
  384.     if ( ( newSize = GrowWindow ( window, hitPt, & sizeRect ) ) != 0L )
  385.     {
  386.         //    for some reason, GrowWindow( ) returns a long value,
  387.         //    but it's really a Point
  388.  
  389.         Resize ( * ( Point * ) & newSize, window ) ;
  390.     }
  391. }
  392.  
  393. void DoZoom ( SInt16 partCode, WindowRef window )
  394. {
  395.     DocumentHandle    hDocument;
  396.     GrafPtr            savePort;
  397.     Rect            r;
  398.  
  399.     GetPort( &savePort );
  400.     SetPortWindowPort( window );
  401.  
  402.     hDocument = GetWindowDocument(window);
  403.  
  404.     r = GetWindowPort( window )->portRect;
  405.     EraseRect( &r );
  406.     HideControl( (*hDocument)->scrollBars[ kVertical ] );
  407.     HideControl( (*hDocument)->scrollBars[ kHorizontal ] );
  408.  
  409.     ZoomWindow( window, partCode, false );
  410.  
  411.     ViewChanged( window );
  412.     CalcTextRect( window, &r );
  413.     InvalRect( &r );
  414.  
  415.     SetPort( savePort );
  416. }
  417.  
  418. // this is a callback tourine called by the Toolbox Control Manager
  419. // move the scroll bar thumb and scroll the text accordingly
  420.  
  421. static pascal void ScrollProc ( ControlRef bar, ControlPartCode partCode )
  422. {
  423.     SInt32 value, step ;
  424.  
  425.     if ( partCode == kControlNoPart )
  426.     {
  427.         return ;
  428.     }
  429.  
  430.     value = LCGetValue ( bar ) ;
  431.     step = sScrollStep ;
  432.  
  433.     if ( ( ( value < LCGetMax ( bar ) ) && ( step > 0 ) ) ||
  434.          ( ( value > 0 ) && ( step < 0 ) ) )
  435.     {
  436.         LCSetValue ( bar, value + step ) ;
  437.         ScrollBarChanged ( FrontWindow ( ) ) ;
  438.     }
  439. }
  440.  
  441. static SInt32 SendControlMessage ( ControlRef inControl, SInt16 inMessage, SInt32 inParam )
  442. {
  443.     GrafPtr savePort ;
  444.     Handle cdef ;
  445.     SInt32 result ;
  446.     SInt8 saveState ;
  447.  
  448.     //    get a handle to the control definition procedure
  449.     cdef = ( * inControl ) -> contrlDefProc ;
  450.  
  451.     //    make sure the CDEF is loaded
  452.     if ( * cdef == nil )
  453.     {
  454.         LoadResource ( cdef ) ;
  455.         if ( * cdef == nil )
  456.         {
  457.             return 0 ;        //    emergency exit (couldn't load CDEF)
  458.         }
  459.     }
  460.  
  461.     //    lock it down
  462.     saveState = HGetState ( cdef ) ;
  463.     HLock ( cdef ) ;
  464.  
  465.     //    set up the port
  466.     GetPort ( & savePort ) ;
  467.     SetPortWindowPort ( ( * inControl ) -> contrlOwner ) ;
  468.  
  469.     //    call the CDEF
  470.     result = CallControlDefProc ( ( ControlDefUPP ) StripAddress ( * cdef ),
  471.                 GetControlVariant ( inControl ), inControl, inMessage, inParam ) ;
  472.  
  473.     //    unlock the CDEF
  474.     HSetState ( cdef, saveState ) ;
  475.  
  476.     //    restore the port
  477.     SetPort ( savePort ) ;
  478.  
  479.     //    return result code
  480.     return result ;
  481. }
  482.  
  483. static void LiveScroll ( ControlRef inControl, Point inHitPt, WindowRef inWindow )
  484. {
  485.     IndicatorDragConstraint constraint ;
  486.     Point mouseLoc ;
  487.     SInt32 initialValue, oldValue, curValue, max ;
  488.     SInt16 scrollRange, delta ;
  489.     Orientation orientation ;
  490.  
  491.     //    hilite the control thumb
  492.     //    this does nothing with the standard System 7.x scroll bar, but is required for
  493.     //    correct visual feedback with the Apple Grayscale Appearance (as implemented by
  494.     //    the Appearance control panel in MacOS 8, or by Aaron/Kaleidoscope)
  495.     HiliteControl ( inControl, kControlIndicatorPart ) ;
  496.  
  497.     //    get limit & slop rects that should be used for dragging the indicator
  498.     //    (see IM: Mac Toolbox Essentials, page 5-114)
  499.     * ( Point * ) & constraint . limitRect = inHitPt ;
  500.     SendControlMessage ( inControl, thumbCntl, ( SInt32 ) & constraint ) ;
  501.  
  502.     //    determine the orientation of the scroll bar
  503.     orientation = ( constraint . axis == kVerticalConstraint ) ? kHorizontal : kVertical ;
  504.  
  505.     //    calculate the area in which the thumb can travel
  506.     if ( orientation == kVertical )
  507.     {
  508.         scrollRange = ( constraint . limitRect . bottom - constraint . limitRect . top ) ;
  509.     }
  510.     else
  511.     {
  512.         scrollRange = ( constraint . limitRect . right - constraint . limitRect . left ) ;
  513.     }
  514.  
  515.     //    get current value & max
  516.     initialValue = oldValue = curValue = LCGetValue ( inControl ) ;
  517.     max = LCGetMax ( inControl ) ;
  518.  
  519.     //    mouse tracking loop
  520.     while ( StillDown ( ) )
  521.     {
  522.         //    get current mouse location
  523.         GetMouse ( & mouseLoc ) ;
  524.  
  525.         //    do nothing if the mouse is outside the slop rectangle
  526.         if ( PtInRect ( mouseLoc, & constraint . slopRect ) )
  527.         {
  528.             //    calculate pixel offset relative to initial hit point
  529.             if ( orientation == kVertical )
  530.             {
  531.                 delta = mouseLoc . v - inHitPt . v ;
  532.             }
  533.             else
  534.             {
  535.                 delta = mouseLoc . h - inHitPt . h ;
  536.             }
  537.  
  538.             //    calculate new control value
  539.             curValue = initialValue + FixMul ( max, FixRatio ( delta, scrollRange ) ) ;
  540.             if ( curValue < 0 ) curValue = 0 ;
  541.             if ( curValue > max ) curValue = max ;
  542.         }
  543.  
  544.         if ( curValue != oldValue )
  545.         {
  546.             //    set new control value
  547.             LCSetValue ( inControl, curValue ) ;
  548.             ScrollBarChanged ( inWindow ) ;
  549.             oldValue = curValue ;
  550.         }
  551.     }
  552.  
  553.     //    unhighlight the thumb
  554.     HiliteControl ( inControl, kControlNoPart ) ;
  555. }
  556.  
  557. static void    DoScrollBar ( Point hitPt, EventModifiers modifiers, WindowRef window )
  558. {
  559.     DocumentHandle        hDocument;
  560.     ControlRef            bar = nil;
  561.     LongRect            viewRect;
  562.     ControlPartCode        partCode;
  563.     SInt32                pageSize;
  564.     SInt32                step = 0;
  565.  
  566. #ifdef __cplusplus
  567.     static ControlActionUPP sScrollerUPP = NewControlActionProc( ScrollProc );
  568. #else
  569.     static ControlActionUPP sScrollerUPP = nil;
  570.     if (sScrollerUPP == nil)
  571.     {
  572.         sScrollerUPP = NewControlActionProc( ScrollProc );
  573.     }
  574. #endif
  575.  
  576.     hDocument = GetWindowDocument( window );
  577.     WEGetViewRect( &viewRect, (*hDocument)->we );
  578.  
  579.     //    find out which control was hit (if any) and in which part
  580.     partCode = FindControl( hitPt, window, &bar );
  581.  
  582.     //    if any control was hit, it must be one of our two scroll bars:
  583.     //    find out which and calculate the page size for it
  584.     if ( bar == (*hDocument)->scrollBars[ kVertical ] )
  585.     {
  586.         pageSize = viewRect.bottom - viewRect.top;
  587.     }
  588.     else if ( bar == (*hDocument)->scrollBars[ kHorizontal ] )
  589.     {
  590.         pageSize = viewRect.right - viewRect.left;
  591.     }
  592.     else
  593.     {
  594.         return;        // return immediately if none of our scrollbars was hit
  595.     }
  596.  
  597.     //    dispatch on partCode
  598.     switch ( partCode )
  599.     {
  600.         case kControlIndicatorPart:
  601.         {
  602.             // click in thumb
  603.             if ( modifiers & optionKey )
  604.             {
  605.                 // call TrackControl with no actionProc and adjust text
  606.                 TrackControl ( bar, hitPt, nil ) ;
  607.                 LCSynch ( bar ) ;
  608.                 ScrollBarChanged ( window ) ;
  609.             }
  610.             else
  611.             {
  612.                 LiveScroll ( bar, hitPt, window ) ;
  613.             }
  614.             return;
  615.         }
  616.  
  617.         case kControlUpButtonPart:
  618.         {
  619.             step = - ( ( modifiers & optionKey ) ? 1 : kScrollDelta ) ;
  620.             break ;
  621.         }
  622.  
  623.         case kControlDownButtonPart:
  624.         {
  625.             step = + ( ( modifiers & optionKey ) ? 1 : kScrollDelta ) ;
  626.             break ;
  627.         }
  628.  
  629.         case kControlPageUpPart:
  630.         {
  631.             step = - ( pageSize - kScrollDelta ) ;
  632.             break ;
  633.         }
  634.  
  635.         case kControlPageDownPart:
  636.         {
  637.             step = + ( pageSize - kScrollDelta ) ;
  638.             break ;
  639.         }
  640.  
  641.     }    // switch
  642.  
  643.     //    save step in a static variable for our ScrollProc callback
  644.     sScrollStep = step ;
  645.  
  646.     //    track the mouse
  647.     TrackControl ( bar, hitPt, sScrollerUPP ) ;
  648. }
  649.  
  650. /*
  651.     This is a callback routine called whenever the text is scrolled automaticall.
  652.     Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE
  653.     in many different circumstances, and we want to be notified when this happens
  654.     so we can adjust the scroll bars
  655. */
  656.  
  657. static pascal void TextScrolled ( WEReference we )
  658. {
  659.     WindowRef window = nil ;
  660.  
  661.     //    retrieve the window pointer stored in the WE instance as a "reference constant"
  662.     if ( WEGetInfo( weRefCon, & window, we ) != noErr )
  663.     {
  664.         return ;
  665.     }
  666.  
  667.     //    make sure the scroll bars are in synch with the destination rectangle
  668.     AdjustBars ( window ) ;
  669. }
  670.  
  671. Boolean    DoContent ( Point hitPt, const EventRecord * event, WindowRef window )
  672. {
  673.     WEReference        we = GetWindowWE ( window ) ;
  674.     Rect            textRect ;
  675.     GrafPtr            savePort ;
  676.     Boolean            isMyClick = false ;
  677.  
  678.     //    set up the port
  679.     GetPort ( & savePort ) ;
  680.     SetPortWindowPort ( window ) ;
  681.  
  682.     //    convert the point to local coordinates
  683.     GlobalToLocal ( & hitPt ) ;
  684.  
  685.     //    a click in an inactive window should normally activate it,
  686.     //    but the availability of the Drag Manager introduces an exception to this rule:
  687.     //    a click in the background selection may start a drag gesture,
  688.     //    without activating the window
  689.  
  690.     if ( IsWindowHilited ( window ) )
  691.     {
  692.         isMyClick = true ;            //    active window -> always handle click
  693.     }
  694.     else if ( gHasDragAndDrop )
  695.     {
  696.         SInt32 selStart, selEnd ;
  697.         RgnHandle selRgn ;
  698.  
  699.         WEGetSelection ( & selStart, & selEnd, we ) ;
  700.         selRgn = WEGetHiliteRgn ( selStart, selEnd, we ) ;
  701.         isMyClick = PtInRgn ( hitPt, selRgn ) && WaitMouseMoved ( event -> where ) ;
  702.         DisposeRgn ( selRgn ) ;
  703.     }
  704.  
  705.     if ( isMyClick )
  706.     {
  707.         CalcTextRect ( window, & textRect ) ;
  708.  
  709.         if ( PtInRect ( hitPt, & textRect ) )
  710.         {
  711.             WEClick ( hitPt, event -> modifiers, event -> when, we ) ;
  712.         }
  713.         else
  714.         {
  715.             DoScrollBar ( hitPt, event -> modifiers, window ) ;
  716.         }
  717.     }
  718.  
  719.     //    restore the port
  720.     SetPort ( savePort ) ;
  721.  
  722.     //    return true if the click should activate this window
  723.     return ! isMyClick ;
  724. }
  725.  
  726. static void    DoScrollKey ( SInt16 keyCode, WindowRef window )
  727. {
  728.     DocumentHandle        hDocument ;
  729.     ControlRef            bar ;
  730.     SInt32                value ;
  731.     LongRect            viewRect ;
  732.  
  733.     hDocument = GetWindowDocument ( window ) ;
  734.     bar = ( * hDocument ) -> scrollBars [ kVertical ] ;
  735.  
  736.     //    get current scroll bar value
  737.     value = LCGetValue ( bar ) ;
  738.  
  739.     //    get text view rect
  740.     WEGetViewRect ( & viewRect, ( * hDocument ) -> we ) ;
  741.  
  742.     switch ( keyCode )
  743.     {
  744.  
  745.         case keyPgUp:
  746.         {
  747.             value -= ( viewRect . bottom - viewRect . top ) - kScrollDelta ;
  748.             break ;
  749.         }
  750.  
  751.         case keyPgDn:
  752.         {
  753.             value += ( viewRect . bottom - viewRect . top ) - kScrollDelta ;
  754.             break ;
  755.         }
  756.  
  757.         case keyHome:
  758.         {
  759.             value = 0 ;
  760.             break ;
  761.         }
  762.  
  763.         case keyEnd:
  764.         {
  765.             value = LONG_MAX ;
  766.             break ;
  767.         }
  768.     }    // switch
  769.  
  770.     //    set the new scroll bar value and scroll the text pane accordingly
  771.  
  772.     LCSetValue ( bar, value ) ;
  773.     ScrollBarChanged ( window ) ;
  774. }
  775.  
  776. void DoKey ( SInt16 key, const EventRecord * event )
  777. {
  778.     WindowRef window ;
  779.     SInt16 keyCode ;
  780.  
  781.     //    do nothing if no window is active
  782.     if ( ( window = FrontWindow ( ) ) == nil )
  783.         return;
  784.  
  785.     //    extract virtual key code from event record
  786.     keyCode = ( event->message & keyCodeMask ) >> 8 ;
  787.  
  788.     // page movement keys are handled by DoScrollKey()
  789.     switch ( keyCode )
  790.     {
  791.         case keyPgUp:
  792.         case keyPgDn:
  793.         case keyHome:
  794.         case keyEnd:
  795.         {
  796.             DoScrollKey ( keyCode, window ) ;
  797.             break ;
  798.         }
  799.  
  800.         default:
  801.         {
  802.             WEKey ( key, event -> modifiers, GetWindowWE (window) ) ;
  803.             break ;
  804.         }
  805.     }
  806. }
  807.  
  808. void DoUpdate ( WindowRef window )
  809. {
  810.     GrafPtr        savePort ;
  811.     RgnHandle    updateRgn ;
  812.  
  813.     // if we have no windows, there's nothing to update!
  814.     if ( window == nil )
  815.     {
  816.         return ;
  817.     }
  818.  
  819.     // save the old drawing port
  820.     GetPort ( & savePort ) ;
  821.     SetPortWindowPort ( window ) ;
  822.  
  823.     // notify everything that we're doing an update.
  824.     BeginUpdate ( window ) ;
  825.  
  826.     // BeginUpdate sets the window port visRgn to the region to update
  827.     updateRgn = GetWindowPort ( window ) -> visRgn ;
  828.  
  829.     if ( ! EmptyRgn ( updateRgn ) )    // if it's not an empty region, let's update it!
  830.     {
  831.         // erase the update region
  832.         EraseRgn ( updateRgn ) ;
  833.  
  834.         //    draw scroll bars
  835.         UpdateControls ( window, updateRgn ) ;
  836.  
  837.         //    draw grow icon
  838.         MyDrawGrowIcon ( window, false ) ;
  839.  
  840.         //    draw text
  841.         WEUpdate ( updateRgn, GetWindowWE ( window ) ) ;
  842.     }
  843.  
  844.     // tell everything we're done updating
  845.     EndUpdate ( window ) ;
  846.  
  847.     // restore the old graphics port
  848.     SetPort ( savePort ) ;
  849. }
  850.  
  851. void DoActivate ( Boolean isActivating, WindowRef window )
  852. {
  853.     DocumentHandle        hDocument ;
  854.     WEReference            we ;
  855.     GrafPtr                savePort ;
  856.     Rect                barRect ;
  857.     ControlPartCode        barHilite ;
  858.     SInt16                menuID ;
  859.     Orientation            orientation ;
  860.  
  861.     // if this is not one of our document windows, nothing to do here...
  862.     if ( ( hDocument = GetWindowDocument ( window ) ) == nil )
  863.     {
  864.         return ;
  865.     }
  866.     we = ( * hDocument ) -> we ;
  867.  
  868.     //    sanity check: do nothing if required activation state
  869.     //    is the same as the current activation state
  870.     if ( isActivating == WEIsActive ( we ) )
  871.     {
  872.         return ;
  873.     }
  874.  
  875.     //     set up the port
  876.     GetPort ( & savePort ) ;
  877.     SetPortWindowPort ( window ) ;
  878.  
  879.     // activate or deactivate the text (and any other relevant stuff) depending on just
  880.     // what we're doing here...
  881.     if ( isActivating )
  882.     {
  883.         WEActivate ( we ) ;
  884.         barHilite = kControlNoPart ;
  885.     }
  886.     else
  887.     {
  888.         WEDeactivate ( we ) ;
  889.         barHilite = kControlDisabledPart ;
  890.     }
  891.  
  892.     //    redraw the grow icon (and validate its rect)
  893.     MyDrawGrowIcon ( window, true ) ;
  894.  
  895.     //    redraw the scroll bars with the new highlighting (and validate their rects)
  896.     for ( orientation = kVertical ; orientation <= kHorizontal ; orientation ++ )
  897.     {
  898.         HiliteControl ( ( * hDocument ) -> scrollBars [ orientation ], barHilite ) ;
  899.         CalcScrollBarRect ( window, orientation, & barRect ) ;
  900.         ValidRect ( & barRect ) ;
  901.     }
  902.  
  903.     //    if activating, undim text-related menus
  904.     if ( isActivating )
  905.     {
  906.         for ( menuID = kMenuEdit ; menuID <= kMenuFeatures ; menuID ++ )
  907.         {
  908.             EnableItem ( GetMenuHandle ( menuID ), 0 ) ;
  909.         }
  910.     }
  911.  
  912.     // invalidate the menu bar
  913.     InvalMenuBar ( ) ;
  914.  
  915.     // restore the old graphics port..
  916.     SetPort ( savePort ) ;
  917. }
  918.  
  919. OSErr CreateWindow ( const FSSpec * pFileSpec )
  920. {
  921.     DocumentHandle    hDocument = nil ;
  922.     WindowRef        window = nil ;
  923.     AliasHandle        alias = nil ;
  924.     WEReference        we = nil ;
  925.     ControlRef        bar = nil ;
  926.     FInfo            fileInfo ;
  927.     Rect            textRect ;
  928.     LongRect        lr ;
  929.     Orientation        orientation ;
  930.     OSErr            err ;
  931.  
  932. #ifdef __cplusplus
  933.     static WEScrollUPP sScrollerUPP = NewWEScrollProc ( TextScrolled ) ;
  934. #else
  935.     static WEScrollUPP sScrollerUPP = nil ;
  936.     if ( sScrollerUPP == nil )
  937.     {
  938.         sScrollerUPP = NewWEScrollProc ( TextScrolled ) ;
  939.     }
  940. #endif
  941.  
  942.     //    allocate a relocateable block to hold a document record
  943.     hDocument = ( DocumentHandle ) NewHandleClear ( sizeof ( DocumentRecord ) ) ;
  944.     if ( ( err = MemError( ) ) != noErr )
  945.     {
  946.         goto cleanup ;
  947.     }
  948.  
  949.     //    create the window from a 'WIND' template: the window is initially invisible
  950.     //    if ColorQuickDraw is available, create a color window
  951.     if ( gHasColorQD )
  952.     {
  953.         window = GetNewCWindow ( kWindowTemplateID, nil, ( WindowRef ) -1L ) ;
  954.     }
  955.     else
  956.     {
  957.         window = GetNewWindow ( kWindowTemplateID, nil, ( WindowRef ) -1L ) ;
  958.     }
  959.  
  960.     //    make sure we got a window
  961.     if ( window == nil )
  962.     {
  963.         err = memFullErr ;
  964.         goto cleanup ;
  965.     }
  966.  
  967.     // link the document record to the window and the other way around
  968.     SetWRefCon ( window, ( SInt32 ) hDocument ) ;
  969.     ( * hDocument ) -> owner = window ;
  970.  
  971.     // we got a window, so tell QuickDraw where to draw...
  972.     SetPortWindowPort ( window ) ;
  973.  
  974.     //    calculate the text rectangle
  975.     CalcTextRect ( window, & textRect ) ;
  976.     WERectToLongRect ( & textRect, & lr ) ;
  977.  
  978.     //    create a new WASTE instance
  979.     if ( ( err = WENew ( & lr, & lr, weDoAutoScroll +
  980.                                      weDoOutlineHilite +
  981.                                      weDoUndo +
  982.                                      weDoIntCutAndPaste +
  983.                                      weDoDragAndDrop +
  984.                                      weDoUseTempMem +
  985.                                      weDoDrawOffscreen, & we) ) != noErr )
  986.     {
  987.         goto cleanup ;
  988.     }
  989.  
  990.     //    save a reference to the window in the WE instance
  991.     if ( ( err = WESetInfo ( weRefCon, & window, we ) ) != noErr )
  992.     {
  993.         goto cleanup ;
  994.     }
  995.  
  996.     //    now the other way around:  save the WE reference in the document record
  997.     ( * hDocument ) -> we = we ;
  998.  
  999.     //    set up our scroll callback
  1000.     if ( ( err = WESetInfo ( weScrollProc, & sScrollerUPP, we ) ) != noErr )
  1001.     {
  1002.         goto cleanup ;
  1003.     }
  1004.  
  1005.     //    create the scroll bars from a control template
  1006.     for ( orientation = kVertical ; orientation <= kHorizontal; orientation ++ )
  1007.     {
  1008.         if ( ( bar = GetNewControl ( kScrollBarTemplateID, window ) ) == nil )
  1009.         {
  1010.             err = memFullErr ;
  1011.             goto cleanup ;
  1012.         }
  1013.         HiliteControl ( bar, kControlDisabledPart ) ;
  1014.  
  1015.         //    attach a LongControl record to the scroll bar:  this allows us to use long
  1016.         //    settings and thus scroll text taller than 32,767 pixels
  1017.         if ( ( err = LCAttach ( bar ) ) != noErr )
  1018.         {
  1019.             goto cleanup;
  1020.         }
  1021.  
  1022.         //    save control handle in the document record
  1023.         ( * hDocument ) -> scrollBars [ orientation ] = bar ;
  1024.  
  1025.     }    // for
  1026.  
  1027.     //    ViewChanged adjusts the scroll bars rectangles to the window frame
  1028.     ViewChanged ( window ) ;
  1029.  
  1030.     //    if pFileSpec is not nil, it points to a file to read, so let's read it!
  1031.     if ( pFileSpec != nil )
  1032.     {
  1033.         // turn the cursor into a wristwatch because this can be a lengthy operation
  1034.         SetCursor ( * GetCursor ( watchCursor ) ) ;
  1035.  
  1036.         //    retrieve file infomation
  1037.         if ( ( err = FSpGetFInfo ( pFileSpec, & fileInfo ) ) != noErr )
  1038.         {
  1039.             goto cleanup ;
  1040.         }
  1041.  
  1042.         //    make sure we recognize the file type
  1043.         if ( ( fileInfo . fdType != kTypeText ) && ( fileInfo . fdType != ftSimpleTextDocument ) )
  1044.         {
  1045.             err = badFileFormat ;
  1046.             goto cleanup ;
  1047.         }
  1048.  
  1049.         //    read in the file
  1050.         if ( ( err = ReadTextFile ( pFileSpec, we ) ) != noErr )
  1051.         {
  1052.             goto cleanup ;
  1053.         }
  1054.  
  1055.         //    set the window title to the file name
  1056.         SetWTitle ( window, pFileSpec -> name ) ;
  1057.  
  1058.         //    create an alias to keep track of the file
  1059.         if ( ( err = NewAlias ( nil, pFileSpec, & alias ) ) != noErr )
  1060.         {
  1061.             goto cleanup ;
  1062.         }
  1063.         ( * hDocument ) -> fileAlias = ( Handle ) alias ;
  1064.  
  1065.         //    if the file is a read-only file, go ahead and enable those flags
  1066.         if ( fileInfo . fdType == ftSimpleTextDocument )
  1067.         {
  1068.             WEFeatureFlag ( weFReadOnly, weBitSet, we ) ;
  1069.         }
  1070.  
  1071.         //    let's make sure the cursor is happy...
  1072.         SetCursor ( & qd . arrow ) ;
  1073.     }
  1074.  
  1075.     //    adjust scroll bar settings based on the total text height
  1076.     AdjustBars ( window ) ;
  1077.  
  1078.     //    finally!  show the document window
  1079.     ShowWindow ( window ) ;
  1080.  
  1081. cleanup:
  1082.     if ( err != noErr )
  1083.     {
  1084.         ErrorAlert ( err ) ;
  1085.     }
  1086.     return err ;
  1087. }
  1088.  
  1089. void DestroyWindow ( WindowRef window )
  1090. {
  1091.     DocumentHandle    hDocument ;
  1092.     SInt16            menuID ;
  1093.  
  1094.     hDocument = GetWindowDocument ( window ) ;
  1095.  
  1096.     //    destroy the WASTE instance
  1097.     WEDispose ( ( * hDocument ) -> we ) ;
  1098.  
  1099.     //    destory the LongControl records attached to the scroll bars
  1100.     LCDetach ( ( * hDocument ) -> scrollBars [ kVertical ] ) ;
  1101.     LCDetach ( ( * hDocument ) -> scrollBars [ kHorizontal ] ) ;
  1102.  
  1103.     //    dispose of the file alias, if any
  1104.     ForgetHandle ( & ( ( * hDocument ) -> fileAlias ) ) ;
  1105.  
  1106.     //    destroy the window record and all associated data structures
  1107.     DisposeWindow ( window ) ;
  1108.  
  1109.     //    finally, dispose of the document record
  1110.     DisposeHandle ( ( Handle ) hDocument ) ;
  1111.  
  1112.     // adjust the menus to suit
  1113.     for ( menuID = kMenuFont ; menuID <= kMenuFeatures ; menuID ++ )
  1114.     {
  1115.         DisableItem ( GetMenuHandle ( menuID ), 0 ) ;
  1116.     }
  1117.     InvalMenuBar ( ) ;
  1118. }
  1119.